from langchain_core.tools import tool
from typing import Annotated, Optional
import os
import logging
from pathlib import Path

logger = logging.getLogger(__name__)

WORKSPACE_ROOT = os.path.join(os.path.dirname(os.path.dirname(__file__)), "workspace")
os.makedirs(WORKSPACE_ROOT, exist_ok=True)

def _safe_path(path: str) -> Path:
    """确保路径在工作区内"""
    full_path = Path(WORKSPACE_ROOT) / path
    full_path = full_path.resolve()
    if not str(full_path).startswith(str(Path(WORKSPACE_ROOT).resolve())):
        raise ValueError("路径必须在工作区内")
    return full_path

@tool
def ls(
    path: Annotated[str, "目录路径，相对于工作区根目录"] = "."
) -> dict:
    """列出目录内容
    
    列出指定目录下的文件和子目录。
    """
    try:
        target = _safe_path(path)
        if not target.exists():
            return {"success": False, "error": "路径不存在"}
        if not target.is_dir():
            return {"success": False, "error": "不是目录"}
        
        items = []
        for item in target.iterdir():
            items.append({
                "name": item.name,
                "type": "dir" if item.is_dir() else "file",
                "size": item.stat().st_size if item.is_file() else None
            })
        
        logger.info(f"[file_system] 列出目录: {path}")
        return {"success": True, "path": path, "items": items}
    except Exception as e:
        logger.error(f"[file_system] ls失败: {e}")
        return {"success": False, "error": str(e)}

@tool
def read_file(
    path: Annotated[str, "文件路径，相对于工作区根目录"]
) -> dict:
    """读取文件内容
    
    读取指定文件的完整内容。
    """
    try:
        target = _safe_path(path)
        if not target.exists():
            return {"success": False, "error": "文件不存在"}
        if not target.is_file():
            return {"success": False, "error": "不是文件"}
        
        content = target.read_text(encoding="utf-8")
        logger.info(f"[file_system] 读取文件: {path}")
        return {
            "success": True,
            "path": path,
            "content": content,
            "size": len(content)
        }
    except Exception as e:
        logger.error(f"[file_system] 读取失败: {e}")
        return {"success": False, "error": str(e)}

@tool
def write_file(
    path: Annotated[str, "文件路径，相对于工作区根目录"],
    content: Annotated[str, "文件内容"]
) -> dict:
    """写入文件内容
    
    创建或覆盖文件内容。
    """
    try:
        target = _safe_path(path)
        target.parent.mkdir(parents=True, exist_ok=True)
        target.write_text(content, encoding="utf-8")
        logger.info(f"[file_system] 写入文件: {path}")
        return {
            "success": True,
            "path": path,
            "size": len(content),
            "message": "文件已写入"
        }
    except Exception as e:
        logger.error(f"[file_system] 写入失败: {e}")
        return {"success": False, "error": str(e)}

@tool
def edit_file(
    path: Annotated[str, "文件路径，相对于工作区根目录"],
    old_text: Annotated[str, "要替换的文本"],
    new_text: Annotated[str, "新文本"]
) -> dict:
    """编辑文件内容
    
    在文件中查找并替换文本。
    """
    try:
        target = _safe_path(path)
        if not target.exists():
            return {"success": False, "error": "文件不存在"}
        
        content = target.read_text(encoding="utf-8")
        if old_text not in content:
            return {"success": False, "error": "未找到要替换的文本"}
        
        new_content = content.replace(old_text, new_text)
        target.write_text(new_content, encoding="utf-8")
        logger.info(f"[file_system] 编辑文件: {path}")
        return {
            "success": True,
            "path": path,
            "message": "文件已编辑"
        }
    except Exception as e:
        logger.error(f"[file_system] 编辑失败: {e}")
        return {"success": False, "error": str(e)}

FileSystemTool = [
    ls,
    read_file,
    write_file,
    edit_file
]
